package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 购物车管理
 */
@Service
public class CartServiceImpl implements CartService {


    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private ProductFeignClient productFeignClient;

    //加入购物车
    @Override
    public CartInfo addToCart(Long skuId, Integer skuNum, String userId) {
        //缓存数据的Key值
        String cartKey = cacheCartKey(userId);
        //1:查询 Redis缓存  DB是存在永久  缓存类型使用不当  一个用户对应集合
        // Hash类型  Map user:3:cart = new HashMap   put(k,v)put(k,v)put(k,v)put(k,v)put(k,v)
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartKey,skuId.toString());
        if(null == cartInfo){
            //条件： 当前用户ID  当前库存ID
            cartInfo = cartInfoMapper.selectOne(new QueryWrapper<CartInfo>()
                    .eq("user_id", userId).eq("sku_id", skuId));
        }
        // 2:保存或更新Mysql 判断此商品是否已经添加过购物车中
        if(null != cartInfo){
            //之前此商品 此用户已经加入过购物车中
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //实时更新价格
            BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
            cartInfo.setSkuPrice(skuPrice);
            //选中
            cartInfo.setIsChecked(1);
            //更新DB
            cartInfoMapper.updateById(cartInfo);
        }else{
            //之前此商品 此用户未加入过购物车中
            cartInfo = new CartInfo();
            //购物车数据
            cartInfo.setSkuId(skuId);
            cartInfo.setIsChecked(1);
            cartInfo.setSkuNum(skuNum);
            //实时更新价格
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setUserId(userId);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfoMapper.insert(cartInfo);
        }
        //3:保存Redis缓存
        loadCartCache(userId);
        return cartInfo;
    }



    //设置购物车在缓存中的存活时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey,RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);//500分
    }

    //缓存的Key值  入参：用户ID   表明此购物车是哪个用户的
    private String cacheCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }



    //查询购物车集合
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
//        第一种：未登录  查询临时用户的购物车集合
//        第二种：登录了  查询是真实用户的购物车集合
        //第三种：查询是临时用户的购物车+真实用户的购物车 == 合并后的购物车集合
        //1:判断真实用户是否存在
        if(StringUtils.isEmpty(userId)){
            //未登录 查询临时用户的购物车
            return this.cartList(userTempId);
        }else{
            //登录了 第三种：查询 临时用户的购物车 + 真实用户的购物车 = 合并后的购物车
            //真实用户的id 不是NULL
            if(StringUtils.isEmpty(userTempId)){
                //临时用户的ID是空  返回真实用户的购物车集合
                return this.cartList(userId);
            }else{
                //临时用户的ID不为空 返回 合并后购物车集合
                return this.mergeCartList(userId,userTempId);
            }
        }
    }
    //购物车之选中或取消
    @Override
    public void checkCart(Long skuId, Integer isChecked, String userId) {
        //DB
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);
        cartInfoMapper.update(cartInfo,new QueryWrapper<CartInfo>()
                .eq("user_id",userId).eq("sku_id",skuId));
        //Redis
        String cacheCartKey = this.cacheCartKey(userId);
        CartInfo cartInfo1 = (CartInfo) redisTemplate.opsForHash().get(cacheCartKey, skuId.toString());
        cartInfo1.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cacheCartKey, skuId.toString(),cartInfo1);
    }
    //查询选中的购物车集合
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        String cartKey = this.cacheCartKey(String.valueOf(userId));
        //1:优先从缓存查询
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if(CollectionUtils.isEmpty(cartInfoList)){
            cartInfoList = cartInfoMapper.selectList(new QueryWrapper<CartInfo>()
                    .eq("user_id",userId).eq("is_checked",1));
        }else{
            cartInfoList = cartInfoList.stream().filter((cartInfo) -> {
                if (cartInfo.getIsChecked().intValue() == 1) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());
        }
        //将选中的购物车集合遍历查询实时价格
        cartInfoList.forEach(cartInfo -> {
            BigDecimal skuPrice = productFeignClient.getSkuPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(skuPrice);
        });
        //选中购物车集合
        return cartInfoList;
    }

    //合并后的购物车
    private List<CartInfo> mergeCartList(String userId, String userTempId) {
        //1:临时用户的购物车集合
        List<CartInfo> cartInfoListUserTempId = this.cartList(userTempId);
        //2:真实用户的购物车集合 0
        List<CartInfo> cartInfoListUserId = this.cartList(userId);
        //
        if(CollectionUtils.isEmpty(cartInfoListUserTempId)){
            return cartInfoListUserId;
        }
        //将真实用户的集合转成Map  K：skuId V:CartInfo
        Map<String, CartInfo> cartInfoMapUserId = cartInfoListUserId.stream().collect(
                Collectors.toMap(cartInfo -> cartInfo.getSkuId().toString(), cartInfo -> cartInfo));
        //临时用户的购物车合并到真实用户的购物车中
        for (CartInfo cartInfoUserTempId : cartInfoListUserTempId) {
            CartInfo cartInfoUserId = cartInfoMapUserId.get(cartInfoUserTempId.getSkuId().toString());
            if(null != cartInfoUserId){
                //存在了 追加数量    skuId 库存ID
                cartInfoUserId.setSkuNum(cartInfoUserId.getSkuNum() + cartInfoUserTempId.getSkuNum());
                //判断临时用户的购物车中选中是否为1
                if(cartInfoUserTempId.getIsChecked().intValue() == 1){
                    //选中
                    cartInfoUserId.setIsChecked(1);
                }
                //操作DB  更新真实用户的购物车商品数量
                cartInfoMapper.updateById(cartInfoUserId);
                //操作DB  删除临时用户的购物车数据
                cartInfoMapper.deleteById(cartInfoUserTempId.getId());
            }else{
                //不存在 添加新款
                cartInfoMapUserId.put(cartInfoUserTempId.getSkuId().toString(),cartInfoUserTempId);
                //更新临时用户的购物车中用户ID字段 从临时用户ID 改为真实用户的ID
                cartInfoUserTempId.setUserId(userId);
                cartInfoMapper.updateById(cartInfoUserTempId);
            }
        }
        //统一将临时用户对应的缓存直接删除
        String cacheCartKeyUserTempId = this.cacheCartKey(userTempId);
        String cacheCartKeyUserId = this.cacheCartKey(userId);
        if(redisTemplate.hasKey(cacheCartKeyUserTempId)){
            redisTemplate.delete(cacheCartKeyUserTempId);//临时用户的对应的HashMap全删掉了
            redisTemplate.delete(cacheCartKeyUserId);
        }
        return new ArrayList<>(cartInfoMapUserId.values());
    }

    //根据用户ID （可能是真实用户 可能是临时用户） 查询购物车集合
    public List<CartInfo> cartList(String userId){
        //1:优先查询缓存   Map user:3:cart = new HashMap()  Map (k,v) (k,v)
        String cartKey = cacheCartKey(userId);
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if(CollectionUtils.isEmpty(cartInfoList)){
            cartInfoList = loadCartCache(userId);
        }
        //实时价格
        cartInfoList.forEach(cartInfo -> {
            BigDecimal skuPrice = productFeignClient.getSkuPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(skuPrice);
        });
        //建议：在此处排序  购物车表的ID进行排序  DES 降序  Lomda    1 5 3 7    7 5 3  1
        cartInfoList.sort((cartInfo1,cartInfo2) -> {
            // 总结：  负 0  正       正数：颠倒顺序  0 ：不动  负：不颠倒顺序
            return cartInfo2.getId().toString().compareTo(cartInfo1.getId().toString());
        });
        //最后进行购物车集合返回
        return cartInfoList;

    }
    //导入DB中购物车集合到缓存中
    public List<CartInfo> loadCartCache(String userId){
        String cartKey = cacheCartKey(userId);
        //2:其次再查询db
        List<CartInfo> cartInfoList = cartInfoMapper.
                selectList(new QueryWrapper<CartInfo>().eq("user_id", userId));

        //判断DB是否有购物车集合‘
        if(!CollectionUtils.isEmpty(cartInfoList)){
            //3:持久化购物车集合到缓存中
            Map<String, CartInfo> cartInfoMap = cartInfoList.stream().collect(Collectors.toMap(cartInfo -> {
                return cartInfo.getSkuId().toString();
            }, cartInfo -> {
                return cartInfo;
            }));
            //连接Redis缓存库 只连接一次就把整个HashMap 保存成功了
            redisTemplate.opsForHash().putAll(cartKey,cartInfoMap);//Map  K:skuId.toString V:cartInfo
            //设置过期时间
            setCartKeyExpire(cartKey);
            return cartInfoList;
        }else{
            return new ArrayList<>();
        }
    }

}
